﻿using FDSimpleModelGenerator.IServices;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using FDSimpleModelGenerator.Entities.Exceptions;

namespace FDSimpleModelGenerator.DapperAccessor
{
    /// <summary>
    /// Dapper的访问
    /// </summary>
    public class DapperDbAccessor : IDbAccessor
    {
        private Func<IDbConnection> _connection;
        private IDbTransaction _transaction;
        private IDbConnection _connectionTransaction;
        private int _transactionCount;

        #region 同步操作
        public void Init(Func<IDbConnection> dbConnection)
        {
            _connection = dbConnection;
        }

        public T Get<T>(string sql, object parameter)
        {
            using var conn = _connection();
            return conn.QueryFirst<T>(sql, parameter);
        }

        public IList<T> GetList<T>(string sql, object parameter)
        {
            using var conn = _connection();
            return conn.Query<T>(sql, parameter).ToList();
        }

        public int ExecuteNoneQuery(string sql, object parameter = null, bool isTransaction = false)
        {
            using var conn = isTransaction ? _connectionTransaction : _connection();
            return conn.Execute(sql, parameter);
        }

        public T ExecuteScalar<T>(string sql, object parameter = null, bool isTransaction = false)
        {
            using var conn = isTransaction ? _connectionTransaction : _connection();
            return conn.ExecuteScalar<T>(sql, parameter);
        }
        #endregion

        #region 异步操作
        public Task InitAsync(Func<IDbConnection> dbConnection)
        {
            _connection = dbConnection;
            return Task.CompletedTask;
        }

        public async Task<T> GetAsync<T>(string sql, object parameter)
        {
            using var conn = _connection();
            return await conn.QueryFirstAsync<T>(sql, parameter);
        }

        public async Task<IList<T>> GetListAsync<T>(string sql, object parameter)
        {
            using var conn = _connection();
            return (await conn.QueryAsync<T>(sql, parameter)).ToList();
        }

        public async Task<int> ExecuteNoneQueryAsync(string sql, object parameter = null, bool isTransaction = false)
        {
            using var conn = isTransaction ? _connectionTransaction : _connection();
            return await conn.ExecuteAsync(sql, parameter);
        }

        public async Task<T> ExecuteScalarAsync<T>(string sql, object parameter = null, bool isTransaction = false)
        {
            using var conn = isTransaction ? _connectionTransaction : _connection();
            return await conn.ExecuteScalarAsync<T>(sql, parameter);
        }

        /// <summary>
        /// 开始事务
        /// </summary>
        /// <returns></returns>
        public async Task<IDbConnection> BeginTransaction()
        {
            return await Task.Run(() =>
            {
                if (_connectionTransaction == null)
                {
                    _connectionTransaction = _connection();
                    _connectionTransaction.Open();
                    _transaction = _connectionTransaction.BeginTransaction();
                    _transactionCount = 1;
                }
                else
                {
                    _transactionCount++;
                }

                return _connectionTransaction;
            });
        }

        /// <summary>
        /// 提交事务
        /// </summary>
        /// <returns></returns>
        public async Task<bool> CommitTransaction()
        {
            return await Task.Run(() =>
            {
                if (_connectionTransaction == null || _transaction == null)
                {
                    throw new TransactionException("当前未启用事务，不可提交");
                }

                if (_transactionCount > 0)
                {
                    _transactionCount--;
                }
                else if (_transactionCount == 0)
                {
                    _transaction.Commit();
                    DisposeTransaction();
                }

                return true;
            });
        }

        private void DisposeTransaction()
        {
            _connectionTransaction.Dispose();
            _transaction.Dispose();
            _transaction = null;
            _connectionTransaction = null;
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        /// <returns></returns>
        public async Task<bool> RollbackTransaction()
        {
            return await Task.Run(() =>
            {
                if (_connectionTransaction == null || _transaction == null)
                {
                    throw new TransactionException("当前未启用事务，不可回滚");
                }

                _transaction.Rollback();
                DisposeTransaction();

                return true;
            });
        }
        #endregion
    }
}
